import { ELEMRNT_TYPE, TEXT_TYPE, parseHTML } from "./parse";
const templateAttr = /\{\{\s*(.*)\s*\}\}/

function genText(content) {
  content = content.trim()
  let match
  let arr = []
  while (match = content.match(templateAttr)) {
    // 如果{不是第一个字符，那么就说明有标签内字符串
    if (match.index) {
      arr.push(`"${content.slice(0, match.index)}"`)
    }
    arr.push(`_s(${match[1]})`)

    content = content.slice(match.index + match[0].length)
  }

  // 如果没匹配到{{}}说明没有变量就是文本，直接用就行了
  if (!match && content) {
    arr.push(`"${content}"`)
  }

  return `_v(${arr.join('+')})`
}

function genChild(children) {
  let code = ''
  children.forEach(child => {
    if (child.type === ELEMRNT_TYPE) {
      // debugger
      code = code + ',' + genCode(child)
    } else if (child.type === TEXT_TYPE) {
      // debugger
      code = code + ',' + genText(child.content)
    }
  })
  return code
}

function genAttrs(attrs) {
  if (!attrs.length) {
    return JSON.stringify({})
  }

  let obj = {}
  attrs.forEach(attr => {
    if (attr.name === 'style') {
      let styles = {}
      attr.value.split(";").forEach(item => {
        let style = item.split(":").map(item => item.trim())
        style[0] && (styles[style[0]] = style[1])
      })
      attr.value = styles
    }
    obj[attr.name] = attr.value
  });

  return JSON.stringify(obj)
}

// 生成render函数核心代码
function genCode(node) {
  let code = `_c("${node.tag}",${genAttrs(node.attrs)}${node.children.length ? genChild(node.children) : ""})`

  return code
}

// 编码生成render函数
export function compileToFunction(template) {
  debugger

  // 转化ast语法树
  let ast = parseHTML(template)
  // console.log(ast)

  // console.log(genCode(ast))

  // 需要with(obj) 在with作用域中，所有的属性默认在obj上直接取值，此时，只要调用render的call是new Vue的实例就可以取到{{}}内的变量
  // {{}}内的变量已经转化为_s(...)
  let code = `with(this) {return ${genCode(ast)}}`

  return new Function(code)
}